package com.atguigu.daijia.order.service.impl;

import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.common.constant.SystemConstant;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.model.entity.order.*;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.order.OrderInfoForm;
import com.atguigu.daijia.model.form.order.StartDriveForm;
import com.atguigu.daijia.model.form.order.UpdateOrderBillForm;
import com.atguigu.daijia.model.form.order.UpdateOrderCartForm;
import com.atguigu.daijia.model.vo.base.PageVo;
import com.atguigu.daijia.model.vo.order.*;
import com.atguigu.daijia.order.mapper.OrderBillMapper;
import com.atguigu.daijia.order.mapper.OrderInfoMapper;
import com.atguigu.daijia.order.mapper.OrderProfitsharingMapper;
import com.atguigu.daijia.order.mapper.OrderStatusLogMapper;
import com.atguigu.daijia.order.service.OrderInfoService;
import com.atguigu.daijia.order.service.OrderMonitorService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author 谢忠涵7
 */
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {
   @Autowired
   private OrderInfoMapper orderInfoMapper;
   @Autowired
   private OrderStatusLogMapper orderStatusLogMapper;
   @Autowired
   private RedisTemplate redisTemplate;
   @Autowired
   private RedissonClient redissonClient;
   @Autowired
   private OrderMonitorService orderMonitorService;
   @Autowired
   private OrderBillMapper orderBillMapper;
   @Autowired
   private OrderProfitsharingMapper orderProfitsharingMapper;
    /**
     * 保存订单信息
     */
    @Override
    public Long saveOrderInfo(OrderInfoForm orderInfoForm) {
      LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper.eq(OrderInfo::getOrderNo, orderInfoForm.getOrderNo());
        OrderInfo orderInfo1 = orderInfoMapper.selectOne(queryWrapper);
        if(orderInfo1 !=null){
            return orderInfo1.getId();
        }
        //封装保存订单数据的对象
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoForm, orderInfo);
        String orderNo = UUID.randomUUID().toString()
                .replace("-", "");
        orderInfo.setOrderNo(orderNo);
        orderInfo.setCreateTime(new Date());
        orderInfo.setStatus(OrderStatus.WAITING_ACCEPT.getStatus());
        orderInfoMapper.insert(orderInfo);
        //将信息加入到延迟队列中
        this.cancelHandler(orderInfo.getId());
      //封装订单数据日志
        OrderStatusLog orderStatusLog = new OrderStatusLog();
        orderStatusLog.setOrderId(orderInfo.getId());
        orderStatusLog.setOrderStatus(orderInfo.getStatus());
        orderStatusLog.setOperateTime(new Date());
        orderStatusLogMapper.insert(orderStatusLog);
        //把订单状态标识加到redis中
        redisTemplate.opsForValue().set(RedisConstant.ORDER_ACCEPT_MARK
                +orderStatusLog.getOrderId(),orderStatusLog.getOrderId());
        return orderInfo.getId();
    }

    /**
     * @description: 将信息加入到延迟队列中
     * @author: xiaoxie
     * @date: 2024/11/1 22:02
     * @param: [id]
     * @return: void
     **/
    private void cancelHandler(Long orderId) {
        try {
            //1先创建一个阻塞队列
            RBlockingQueue<String> queueCancel = redissonClient.getBlockingQueue("queue_cancel");
            //2.将阻塞队列加入到延迟队列中
            RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queueCancel);
            //3.将消息加入到延迟队列中
            delayedQueue.offer(orderId.toString(),15,TimeUnit.MINUTES);
        }catch (Exception e) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
    }

    /**
     * 查询订单状态
     */
    @Override
    public Integer getOrderStatus(Long orderId) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId, orderId);
        wrapper.select(OrderInfo::getStatus);
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        //如果订单状态不存在
        if(orderInfo == null) {
            return OrderStatus.NULL_ORDER.getStatus();
        }
        return orderInfo.getStatus();
    }

    /**
     * @description: 司机抢单 为了防止线程安全问题 加 分布式锁
     * @author: xiaoxie
     * @date: 2024/10/28 21:53
     * @param: [driverId, orderId] 司机id 订单id
     * @return: java.lang.Boolean
     **/
    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        //先查询redis该订单是否可以抢单
        Boolean isExit = redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId);
        if(isExit == null || !isExit){
            throw  new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        }
        RLock lock = redissonClient.getLock(RedisConstant.ROB_NEW_ORDER_LOCK + orderId);
        try{
            //尝试获取锁 获取锁等待时间 + 锁过期时间 + 单位
            boolean isTryLock = lock.tryLock(RedisConstant.ROB_NEW_ORDER_LOCK_WAIT_TIME
                    , RedisConstant.ROB_NEW_ORDER_LOCK_LEASE_TIME
                    , TimeUnit.SECONDS);
            if(isTryLock){
                //再次查询防止重复抢单
                Boolean isExit1 = redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId);
                if(isExit1 == null || !isExit1){
                    throw  new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }
                //执行抢单逻辑
                //修改 接单司机id + 司机接单时间 + 订单状态改成已接单 + 删除redis中的标记
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setDriverId(driverId);
                orderInfo.setAcceptTime(new Date());
                orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());
                LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(OrderInfo::getId, orderId);
                int update = orderInfoMapper.update(orderInfo, wrapper);
                if(update != 1){
                    throw  new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }
                //删除redis中的标识
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK + orderId);
            }

        }catch (Exception e) {
            throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        }finally {
            if(lock.isLocked()){
                lock.unlock();
            }
        }
        return true;
    }
    /**
     * 乘客端查找当前订单
     */
    @Override
    public CurrentOrderInfoVo searchCustomerCurrentOrder(Long customerId) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getCustomerId, customerId);
        //并且状态要为正常状态
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus(),
                OrderStatus.UNPAID.getStatus()
        };
        wrapper.in(OrderInfo::getStatus, (Object)statusArray);
        //降序排序,获取到当前第一条订单
        wrapper.orderByDesc(OrderInfo::getId);
        wrapper.last("limit 1");
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        //封装返回的VO对象
        if(null != orderInfo){
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        }else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    /**
     * 司机端查找当前订单
     */
    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, driverId);
        //司机发送完账单，司机端主要流程就走完（当前这些节点，司机端会调整到相应的页面处理逻辑）
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus()
        };
        queryWrapper.in(OrderInfo::getStatus, (Object) statusArray);
        queryWrapper.orderByDesc(OrderInfo::getId);
        queryWrapper.last("limit 1");
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if(null != orderInfo) {
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        } else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getDriverId,driverId);
        wrapper.eq(OrderInfo::getId,orderId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setArriveTime(new Date());
        orderInfo.setStatus(OrderStatus.DRIVER_ARRIVED.getStatus());
        int row = orderInfoMapper.update(orderInfo, wrapper);
        if(row == 1) {
            return true;
        }else {
            throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
        }
    }

    /**
     * 更新车辆信息
     */
    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(updateOrderCartForm, orderInfo);
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,updateOrderCartForm.getOrderId());
        wrapper.eq(OrderInfo::getDriverId, updateOrderCartForm.getDriverId());
        orderInfo.setStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
        int row = orderInfoMapper.update(orderInfo, wrapper);
        if(row == 1) {
            OrderStatusLog orderStatusLog = new OrderStatusLog();
            orderStatusLog.setOrderId(updateOrderCartForm.getOrderId());
            orderStatusLog.setOrderStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
            orderStatusLogMapper.insert(orderStatusLog);
            return true;
        }else {
            throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
        }
    }
    /**
     * @description: 开始代驾服务 修改订单状态
     * @author: xiaoxie
     * @date: 2024/10/30 19:32
     * @param: [startDriveForm]
     * @return: java.lang.Boolean
     **/
    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStartServiceTime(new Date());
        orderInfo.setStatus(OrderStatus.START_SERVICE.getStatus());
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,startDriveForm.getOrderId());
        wrapper.eq(OrderInfo::getDriverId,startDriveForm.getDriverId());
        int update = orderInfoMapper.update(orderInfo, wrapper);
        if(update == 1) {
            //初始化订单监控数据
            OrderMonitor orderMonitor = new OrderMonitor();
            orderMonitor.setOrderId(startDriveForm.getOrderId());
            orderMonitorService.saveOrderMonitor(orderMonitor);
            return true;
        }else {
            throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
        }
    }

    /**
     * 根据时间段获取订单数
     * @return
     */
    @Override
    public Long getOrderNumByTime(String startTime, String endTime) {
        // 查询 startTime<= count < endTime
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(OrderInfo::getStartServiceTime,startTime);
        wrapper.lt(OrderInfo::getStartServiceTime,endTime);
        return orderInfoMapper.selectCount(wrapper);
    }

    /**
     * 结束代驾服务更新订单账单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean endDrive(UpdateOrderBillForm updateOrderBillForm) {
        //1 更新订单信息
        // update order_info set ..... where id=? and driver_id=?
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,updateOrderBillForm.getOrderId());
        wrapper.eq(OrderInfo::getDriverId,updateOrderBillForm.getDriverId());

        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStatus(OrderStatus.END_SERVICE.getStatus());
        orderInfo.setRealAmount(updateOrderBillForm.getTotalAmount());
        orderInfo.setFavourFee(updateOrderBillForm.getFavourFee());
        orderInfo.setRealDistance(updateOrderBillForm.getRealDistance());
        orderInfo.setEndServiceTime(new Date());

        int rows = orderInfoMapper.update(orderInfo, wrapper);

        if(rows == 1) {
            //添加账单数据
            OrderBill orderBill = new OrderBill();
            BeanUtils.copyProperties(updateOrderBillForm,orderBill);
            orderBill.setOrderId(updateOrderBillForm.getOrderId());
            orderBill.setPayAmount(updateOrderBillForm.getTotalAmount());
            orderBillMapper.insert(orderBill);

            //添加分账信息
            OrderProfitsharing orderProfitsharing = new OrderProfitsharing();
            BeanUtils.copyProperties(updateOrderBillForm, orderProfitsharing);
            orderProfitsharing.setOrderId(updateOrderBillForm.getOrderId());
            orderProfitsharing.setRuleId(updateOrderBillForm.getProfitsharingRuleId());
            orderProfitsharing.setStatus(1);
            orderProfitsharingMapper.insert(orderProfitsharing);

        } else {
            throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    /**
     * 获取乘客订单分页列表
     */
    @Override
    public PageVo findCustomerOrderPage(Page<OrderInfo> pageParam, Long customerId) {
        //查询数据库
        IPage<OrderListVo> orderListVoIPage = orderInfoMapper.selectCustomerOrderPage(pageParam, customerId);
        if(orderListVoIPage.getRecords().isEmpty()) {
            return null;
        }
        //封装对象
        return new PageVo(orderListVoIPage.getRecords()
                         ,orderListVoIPage.getPages()
                         ,orderListVoIPage.getTotal());
    }

    /**
     * 获取司机订单分页列表
     */
    @Override
    public PageVo findDriverOrderPage(Page<OrderInfo> pageParam, Long driverId) {
        //查询数据库
        IPage<OrderListVo> orderListVoIPage = orderInfoMapper.selectDriverOrderPage(pageParam, driverId);
        if(orderListVoIPage.getRecords().isEmpty()) {
            return null;
        }
        //封装对象
        return new PageVo(orderListVoIPage.getRecords()
                ,orderListVoIPage.getTotal()
                ,orderListVoIPage.getPages());
    }

    /**
     * 根据订单id获取实际账单信息
     */
    @Override
    public OrderBillVo getOrderBillInfo(Long orderId) {
      LambdaQueryWrapper<OrderBill> wrapper = new LambdaQueryWrapper<>();
      wrapper.eq(OrderBill::getOrderId,orderId);
      OrderBill orderBill = orderBillMapper.selectOne(wrapper);
      //封装对象
      OrderBillVo orderBillVo = new OrderBillVo();
      BeanUtils.copyProperties(orderBill,orderBillVo);
      return orderBillVo;
    }

    /**
     * 根据订单id获取实际分账信息
     */
    @Override
    public OrderProfitsharingVo getOrderProfitsharing(Long orderId) {
        LambdaQueryWrapper<OrderProfitsharing> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderProfitsharing::getOrderId,orderId);
        OrderProfitsharing orderProfitsharing = orderProfitsharingMapper.selectOne(wrapper);
        OrderProfitsharingVo orderProfitsharingVo = new OrderProfitsharingVo();
        BeanUtils.copyProperties(orderProfitsharing,orderProfitsharingVo);
        return orderProfitsharingVo;

    }

    /**
     * 发送账单信息 即修改订单状态即可
     */
    @Override
    public Boolean sendOrderBillInfo(Long orderId, Long driverId) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,orderId);
        wrapper.eq(OrderInfo::getDriverId,driverId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStatus(OrderStatus.UNPAID.getStatus());
        int update = orderInfoMapper.update(orderInfo, wrapper);
        if(update == 1) {
            return true;
        }else {
            throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
        }
    }

    /**
     * 获取账单支付信息
     */
    @Override
    public OrderPayVo getOrderPayVo(String orderNo, Long customerId) {
        OrderPayVo orderPayVo = orderInfoMapper.selectOrderPayVo(orderNo, customerId);
        if(null != orderPayVo) {
            String content = orderPayVo.getStartLocation() + " 到 " + orderPayVo.getEndLocation();
            orderPayVo.setContent(content);
        }
        return orderPayVo;
    }

    @Override
    public void cancelOrder(long orderId) {
        //先获取订单数据
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if(orderInfo != null && Objects.equals(orderInfo.getStatus(), OrderStatus.WAITING_ACCEPT.getStatus())) {
            orderInfo.setStatus(OrderStatus.CANCEL_ORDER.getStatus());
            int row = orderInfoMapper.updateById(orderInfo);
            if(row == 1) {
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK);
            }else {
                throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
            }
        }
        //如果订单状态不为未接单,就不修改
    }
}
